package com.caiyi.financial.nirvana.sms.gateway.cmpp;

import com.caiyi.financial.nirvana.sms.gateway.cmpp.cmpp30.message.CMPP3Message;
import io.netty.buffer.ByteBuf;
import org.apache.commons.lang3.RandomUtils;

import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

public class CMPPMessageTool {

    public static final char[] BYTE_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    private final static long Limited = 0x7fffffffffff0000L;
    private final static AtomicLong sequenceId = new AtomicLong(Math.abs(RandomUtils.nextInt(0, Integer.MAX_VALUE)));

    public static String formatCommandId(int commandId) {
        switch (commandId) {
            case CMPP3Message.CMPP_ACTIVE_TEST:
                return "CMPP_ACTIVE_TEST";
            case CMPP3Message.CMPP_ACTIVE_TEST_RESP:
                return "CMPP_ACTIVE_TEST_RESP";
            case CMPP3Message.CMPP_CONNECT:
                return "CMPP_CONNECT";
            case CMPP3Message.CMPP_CONNECT_RESP:
                return "CMPP_CONNECT_RESP";
            case CMPP3Message.CMPP_DELIVER:
                return "CMPP_DELIVER";
            case CMPP3Message.CMPP_DELIVER_RESP:
                return "CMPP_DELIVER_RESP";
            case CMPP3Message.CMPP_SUBMIT:
                return "CMPP_SUBMIT";
            case CMPP3Message.CMPP_SUBMIT_RESP:
                return "CMPP_SUBMIT_RESP";
            case CMPP3Message.CMPP_TERMINATE:
                return "CMPP_TERMINATE";
            case CMPP3Message.CMPP_TERMINATE_RESP:
                return "CMPP_TERMINATE_RESP";
        }
        return "UNKNOWN";
    }

    public static int getMMDDHHMMSS() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        int timestamp = (calendar.get(Calendar.MONTH) + 1) * 0x5f5e100
                + calendar.get(Calendar.DAY_OF_MONTH) * 0xf4240
                + calendar.get(Calendar.HOUR_OF_DAY) * 10000
                + calendar.get(Calendar.MINUTE) * 100
                + calendar.get(Calendar.SECOND);
        return timestamp;
    }

    public static byte[] Md5(String str) throws Exception {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(str.getBytes());
        return md5.digest();
    }

    public static void writeBytes2Buffer(ByteBuf buffer, byte[] bytes, int length) {
        if (null == buffer || null == bytes || length <= 0) {
            return;
        }
        int byteLength = bytes.length;
        if (byteLength >= length) {
            buffer.writeBytes(bytes, 0, length);
        } else {
            buffer.writeBytes(bytes);
            buffer.writeZero(length - byteLength);
        }
    }

    /**
     * HEX字符串转换成byte数组
     */
    public static byte[] transHexString2bytes(String content) throws NumberFormatException {
        int length = content.length();
        if (length == 0) {
            return new byte[0];
        }
        byte[] bytes = new byte[length / 2];
        for (int i = 0; i < bytes.length; i++) {
            String temp = content.substring(i * 2, i * 2 + 2);
            int hex = 0;
            try {
                hex = Integer.parseInt(temp, 16);
            } catch (NumberFormatException e) {
                throw e;
            }
            bytes[i] = (byte) hex;
        }
        return bytes;
    }

    /**
     * byte数组转换成HEX字符串
     */
    public static String transBytes2HexString(byte[] bytes) throws NumberFormatException {
        if (bytes.length == 0) {
            return null;
        }
        StringBuffer strBuf = new StringBuffer();
        int bit;
        for (int i = 0; i < bytes.length; i++) {
            bit = (bytes[i] & 0xf0) >> 4;
            strBuf.append(BYTE_CHAR[bit]);
            bit = bytes[i] & 0x0f;
            strBuf.append(BYTE_CHAR[bit]);
        }
        return strBuf.toString();
    }

    /***
     * 去除buffer末尾的0x0
     */
    public static byte[] trimStringBufferRightZeros(byte[] buffer) {
        int offset = buffer.length - 1;
        while (offset > 0) {
            if (buffer[offset] != 0x0) {
                break;
            }
            offset--;
        }
        return Arrays.copyOf(buffer, offset + 1);
    }

    public static long getSequenceNo() {
        return getNextAtomicValue(sequenceId, Limited);
    }

    /**
     * 实现AtomicLong对象的线程安全循环自增
     *
     * @param atomicObj 需要自增的Atomic对象
     * @param limited   最大值
     */
    public static long getNextAtomicValue(AtomicLong atomicObj, long limited) {
        long ret = atomicObj.getAndIncrement();

        if (ret > limited) { // Long.MAX_VALUE - 0xfff
            synchronized (atomicObj) {
                //双重判断，只能有一个线程更新值
                if (atomicObj.get() > limited) {
                    atomicObj.set(0);
                    return 0;
                } else {
                    return atomicObj.getAndIncrement();
                }
            }
        } else {
            return ret;
        }
    }

    public static byte getOne() {
        return (byte) (getSequenceNo() & 0xff);
    }

}